#include "KPBR.h"

#include"ObjLoader.h"

#include <stb_image_write.h>

#include <iostream>
#include <ctime>

std::string GetFileName(const kp::Scene& scene);

int main() {

	std::cout << R"( Welcome to
  _  ______  ____  ____  
 | |/ /  _ \| __ )|  _ \ 
 | ' /| |_) |  _ \| |_) |
 | . \|  __/| |_) |  _ < 
 |_|\_\_|   |____/|_| \_\
--------------------------
)";
	// Init scene
	auto film = kp::MakeRef<kp::Film>(2560, 1440);
	float aspect = (float)film->size.w / film->size.h;
	auto camera = kp::MakeRef<kp::PerspectiveCamera>(
		kp::PerspectiveCamera(kp::Mat4::lookAt({ 0.0f,0.0f,7.5f }, { 0.0f,0.0f,-1.0f }),
			{ {-1,-1.0f / aspect},{1,1.0f / aspect} }, 0.0f, 0.0f, 0.0f, 1.0f, 75, *film));
	auto prims = kp::MakeRef<kp::ListAccel>(kp::ListAccel());

	auto trans1 = kp::Transform::Create({ 0.0f,-2.8f,-1.2f }, { 2.0f,2.0f,2.0f }, { 1.0f,1.0f,1.0f }, kp::DegreesToRadians(45.0f));
	auto trans2 = kp::Transform::Create({ -2.0f,1.8f,-1.2f }, { 2.0f,2.0f,2.0f }, { 1.0f,1.0f,1.0f }, kp::DegreesToRadians(-45.0f));
	auto trans3 = kp::Transform::Create({ 3.0f,-0.8f,-1.2f }, { 2.0f,2.0f,2.0f }, { 1.0f,1.0f,1.0f }, kp::DegreesToRadians(-15.0f));
	auto trans4 = kp::Transform::Create({ 0.0f,0.0f,-0.5f }, { 2.0f,2.0f,2.0f }, { 1.0f,0.0f,0.0f }, kp::DegreesToRadians(0.0f));
	auto objl = ObjLoader("data/torus.obj");
	auto box1 = objl.get(trans1);
	auto box2 = objl.get(trans2);
	auto box3 = objl.get(trans3);
	auto box4 = objl.get(trans4);
	prims->push_back(box1);
	prims->push_back(box2);
	prims->push_back(box3);
	prims->push_back(box4);
	auto bvh = kp::MakeRef<kp::BVHAccel>(kp::BVHAccel(prims->primitives, 8, kp::BVHAccel::SplitMethod::Middle));
	auto scene = kp::MakeRef<kp::Scene>(kp::Scene("default_scene", camera, bvh));

	// Init tracer
	auto tracer = kp::singleton<kp::MultiTracer>::getInstance(kp::MultiTracer(16));
	auto sampler = kp::MakeRef<kp::PixelSampler>(100);
	auto& state = tracer->state;
	auto start_time = std::clock();
	tracer->render(scene, sampler, film);

	printf("Primitives numbers: %lld\n", bvh->size());
	printf("Render task(s): %lld\n", state.tasknum);
	// track progress
	while (true) {
		auto prog = state.progression();

		printf("Progress: %d/%d, (%.4f%%)                ",
			prog.current, prog.total, 100.0f * (float)prog.current / (float)prog.total);

		if (prog.current >= prog.total) {
			printf("\n");
			break;
		}
		printf("\r");
	}
	printf("spend time: %.3fs\n", (float)(std::clock() - start_time) / 1000.0f);

	// output image
	kp::ImageFilm img = *film;
	auto fileStr = GetFileName(*scene);
	stbi_flip_vertically_on_write(false);
	auto writeResult = stbi_write_jpg(fileStr.c_str(),
		(int)img.width, (int)img.height, (int)img.channel, img.data, 0);
	img.free();
	if (writeResult) {
		std::cout << "Output File Path: " << fileStr << std::endl;
		system(("start " + fileStr).c_str());
	}
	else
		std::cout << "Output Failed." << std::endl;

}

std::string GetFileName(const kp::Scene& scene)
{
	char timeCh[64] = { '\0' };
	time_t rawTime;
	std::time(&rawTime);
	std::strftime(timeCh, 64, "%Y.%m.%d-%H.%M.%S", std::localtime(&rawTime));
	std::string timeStr(timeCh);
	std::string appType;

#if defined KP_DEBUG
	appType = "Debug";
#elif defined KP_RELEASE
	appType = "Release";
#endif

	return "ImgOut/" + timeStr + "_" + appType + "_" + scene.name + ".jpg";
}